//首页导航页面代码
function setNavVariables({ _, systemPageNames = {},   otherPageNames = {},addVars={}}) {//设置导航菜单参数  
  let systemPageNames_secondList = new Map(), otherPageNames_secondList = new Map(), barDatas = new Map()
  let corpid = "ding133adf9bcfaef5f2ffe93478753d9884", isRenderNav =  false
  let otherVariables = {
     isMobile: _.utils.isMobile(),
     isDingTalk:window.navigator && /dingtalk/i.test(window.navigator.userAgent),
     ... window.loginUser,
     appType:window.pageConfig.appType || window.g_config.appKey,//应用id
     formUuid:window.pageConfig.formUuid || window.g_config.index//页面id
  }
  Object.entries(systemPageNames).forEach(([key, value]) => {
    if (typeof value !== "string") {//如果不是对象
      Object.entries(value).forEach(([keyChild, valueChild]) => {
        systemPageNames_secondList.set(keyChild, getNavURL({url:valueChild, corpid, isRenderNav}))
        barDatas.set (keyChild, getNavURL({url:valueChild, corpid, isRenderNav}))
      })
    } else {
      barDatas.set (key, getNavURL({url:value, corpid, isRenderNav}))
    }
  })
  Object.entries(otherPageNames).forEach(([key, value]) => {
    if (typeof value !== "string") {//如果不是对象
      Object.entries(value).forEach(([keyChild, valueChild]) => {
        otherPageNames_secondList.set(keyChild, getNavURL({url:valueChild, corpid, isRenderNav}))
        barDatas.set (keyChild, getNavURL({url:valueChild, corpid, isRenderNav}))
      })
    } else {
      barDatas.set (key, getNavURL({url:value, corpid, isRenderNav}))
    }
  }) 
 
  _.setState({ barDatas, systemPageNames_secondList, otherPageNames_secondList, searchDatas: barDatas,...addVars, ...otherVariables }  )
}
function getNavURL({ url, corpid, isRenderNav }) {//检查url，是否拼接
  let newURL = url
  const isJoin = /.*http.*/ig.test(url)//控制是否拼接
  if (!isJoin) {
    const base = `https://www.aliwork.com/${window.pageConfig.appType || window.g_config.appKey}/custom/`
    const pamara = `?corpid=${corpid}&isRenderNav=${isRenderNav}`
    newURL = base + url + pamara  
  }
  return newURL
}
function accessCheck({pageName,_}){//权限检查  本页面独有//关键指标看板
  let { barDatas, iFrameURL, getData_limit, userId,   systemPageNames} = _.state
  let isHasAccesses = false
  let selfAccesses = new Map()
  for (const [key, value] of barDatas) {    
    if (getData_limit[key]) {//如果在受限对象里面
      if (getData_limit[key].includes(userId)){//检查登录人是否有权限
        selfAccesses.set(key,value)
        isHasAccesses = true     
      }
       
    } else {//如果不在受限对象里面，直接添加
      selfAccesses.set(key, value)
    }
  };
   // // 权限默认有带参数跳转的页面
  if(pageName && !selfAccesses.has(pageName)  ){
    selfAccesses.set(pageName, barDatas.get(pageName))
  } 
  if(selfAccesses.size === 0){
      _.utils.toast({
      title: '抱歉，暂无权限', // 'success', 'warning', 'error', 'notice', 'help', 'loading'
      type: 'notice',
      size: 'large',
      duration: 2000, // 毫秒, type 为 loding 时无效
    });
  } else {
    iFrameURL = isHasAccesses? selfAccesses.values().next().value :""//默认进入第一个有权限的页面
    if(pageName){//如果携带参数，则跳转参数页面
      iFrameURL = selfAccesses.get(pageName)
    }
  }
  _.setState({ iFrameURL, selfAccesses })
}
function setIframeHeight({ _, fixed_container,outer_container,iframe_self}) {//设置frame高度，避免主页面出现垂直滚动条
  let { isMobile } =_.state
  setTimeout(() => {
    const headerElement = document.getElementById(fixed_container); 
    if (headerElement) {
      let innerHeight = window.innerHeight
      ///计算固定部分元素高度，包括外边距
      let elementHeight = headerElement.offsetHeight;
      let computedStyle = window.getComputedStyle(headerElement);
      let marginTop = parseFloat(computedStyle.marginTop);
      let marginBottom = parseFloat(computedStyle.marginBottom);
      let totalElementHeight = elementHeight + marginTop + marginBottom

      // /计算iframe外容器部分元素外边距
      const iframeElement = document.getElementById(outer_container);
      computedStyle = window.getComputedStyle(iframeElement);
      marginTop = parseFloat(computedStyle.marginTop);
      marginBottom = parseFloat(computedStyle.marginBottom);
      const iframecontent = document.getElementById(iframe_self) //|| iframeElement.childNodes[0];//iframe组件    
      if (iframecontent) {
        iframecontent.setAttribute("style", `height:${isMobile ? innerHeight : innerHeight - totalElementHeight}px`);
      }
    }

  }, 500)
}
function setIframeHeightSinglePage(_,headerDiv,tabDiv,iframeDiv,iframeId) {//设置框架高度,针对一个页面数据管理和输入页面在一个自定义页面情况，输入页面通过框架组件引用
  let { isMobile} = _.state
  setTimeout(()=>{
    const headerElement = document.getElementById(headerDiv);
    if (headerElement) {
      let innerHeight = window.innerHeight
      ///计算固定部分元素高度，包括外边距
      let elementHeight = headerElement.offsetHeight;
      let computedStyle = window.getComputedStyle(headerElement);
      let marginTop = parseFloat(computedStyle.marginTop);
      let marginBottom = parseFloat(computedStyle.marginBottom);
      let totalElementHeight = elementHeight + marginTop + marginBottom

      ///计算表格外容器部分元素外边距
      const tabElement = document.getElementById(tabDiv);
      computedStyle = window.getComputedStyle(tabElement);
      marginTop = parseFloat(computedStyle.marginTop);
      marginBottom = parseFloat(computedStyle.marginBottom);
      _.setState({ maxHeight: innerHeight - totalElementHeight- marginBottom - marginTop  - 80 })//表格最大高度
      // /计算iframe外容器部分元素外边距
      const iframeElement = document.getElementById(iframeDiv);
      computedStyle = window.getComputedStyle(iframeElement);
      marginTop = parseFloat(computedStyle.marginTop);
      marginBottom = parseFloat(computedStyle.marginBottom);
      const iframecontent = document.getElementById(iframeId) //|| iframeElement.childNodes[0];//iframe组件
      if (iframecontent) {        
        iframecontent.setAttribute("style", `height:${isMobile?innerHeight:innerHeight - totalElementHeight - marginBottom - marginTop -30}px`);
      }
    }    
  },500)  
}
function setNavBarDisplay() {////设置操作、导航区域是否可见  
  let isDingTalk = window.navigator && /dingtalk/i.test(window.navigator.userAgent)//是否在钉钉环境下  
  if (!isDingTalk) {//浏览器环境可见
    let classes = [
      '.next-aside-navigation',
      '.next-shell-header',
      'div.next-shell-appbar',
      ".next-shell-action"
    ]
    for (let i = 0; i < classes.length; i++) {
      let target = document.querySelector(classes[i])
      if (target) {       
        target.setAttribute("style", "display: flex !important;")
      }
    }
  }
}
function dingtalk({userId,_}) {//钉钉消息
  let { isMobile, isDingTalk } = _.state
  if (isMobile) {
    let dd = window.dd
    if (dd && isDingTalk) {
      dd.biz.chat.openSingleChat({
        corpId: 'ding133adf9bcfaef5f2ffe93478753d9884', // 企业id,必须是用户所属的企业的corpid
        userId: userId, // 用户的uerid
        onSuccess: function () { },
        onFail: function () { }
      })
    }
  } else {
    _.utils.toast({
      title: '请在移动端操作', // 'success', 'warning', 'error', 'notice', 'help', 'loading'
      type: 'notice',
      size: 'large',
      duration: 3000, // 毫秒, type 为 loding 时无效
    });
  }
}
 function dingTelephone({userId,_}) {//钉钉电话
  let { isMobile, isDingTalk } =_.state
  if (isMobile) {
    let dd = window.dd
    if (dd && isDingTalk) {
      dd.biz.telephone.call({
        corpId: 'ding133adf9bcfaef5f2ffe93478753d9884', // 企业id,必须是用户所属的企业的corpid
        users: [userId],  // 用户的uerid
        onSuccess: function () { },
        onFail: function () { }
      })
    }

  } else {
    _.utils.toast({
      title: '请在移动端操作', // 'success', 'warning', 'error', 'notice', 'help', 'loading'
      type: 'notice',
      size: 'large',
      duration: 3000, // 毫秒, type 为 loding 时无效
    });
  }
}
function telephone({phoneNumber,_}) {//普通电话
  let { isMobile, isDingTalk } = _.state
  if (isMobile) {
    let dd = window.dd
    if (dd && isDingTalk) {
      dd.biz.telephone.showCallMenu({
        phoneNumber: phoneNumber, // 期望拨打的电话号码
        code: '+86', // 国家代号，中国是+86   
        showDingCall: false, // 是否显示钉钉电话   
        onSuccess: function () { },
        onFail: function () { }
      })
    }
  } else {
    _.utils.toast({
      title: '请在移动端操作', // 'success', 'warning', 'error', 'notice', 'help', 'loading'
      type: 'notice',
      size: 'large',
      duration: 3000, // 毫秒, type 为 loding 时无效
    });
  }
}

 function handleMouseMove(e) {//内容区，导航区鼠标滑过事件，为第二级、第三级导航菜单设置样式为隐藏
  let secondBar = document.getElementById("secondBar");
  if (secondBar) {
    Object.assign(secondBar.style, {
        //   opacity: 0,
        //   visibility: "hidden"
        display: "none"
    });
  }
  let thirdBar = document.getElementById("thirdBar");
  if (thirdBar) {
    Object.assign(thirdBar.style, {
        //   opacity: 0,
        //   visibility: "hidden"
        display: "none"
    });
  }
 
}
// 为多个元素添加事件
function addEvents(elements, useThrottle = true, throttleDelay = 100) {
    // elements参数格式[{element:"元素id",event:"事件名称",handler:"处理函数",handlerName:"函数名称",throttleDelay:"延迟时间"}]
    // useThrottle是否开启节流
    // throttleDelay节流延迟时间
  try {
    if (!Array.isArray(elements)) {
      throw new Error("参数错误，应为对象数组");
    }
    // 验证数组元素结构
    const isValidElement = elements.every(item =>
      item &&
      item.element &&
      item.event &&
      typeof item.event === 'string' &&
      (item.handler || item.handlerName)
    );
    if (!isValidElement) {
      throw new Error("数组元素必须包含 element, event 和 handler/handlerName 属性");
    }
    elements.forEach(item => {    
      let handler;     
        // 支持直接传入处理函数或函数名
      if (item.handler) {
        handler = item.handler;
      } else if (item.handlerName && window[item.handlerName]) {
        handler = window[item.handlerName];//无法直接调用宜搭页面js面板函数，要显式声明为全局函数
      } else {
        throw new Error(`未找到处理函数:${item.handlerName}`);
      }     
      if (useThrottle)   {
        handler = throttle(handler, item.throttleDelay || throttleDelay || 100 ,false);
      }
      // 添加事件监听器
      item.element.addEventListener(item.event, handler);
      // 可选：保存引用以便后续移除
      if (!item.element._eventHandlers) {
        item.element._eventHandlers = [];
      }
      item.element._eventHandlers.push({
        event: item.event,
        handler: handler
      });  
    });

  } catch (e) {
    console.error("事件添加失败:", e.message);
    throw new Error(e.message)
  }
}
// 节流函数
function throttle(func, throttleDelay = 100,isExecuteAgain = true) {
    // func需要节流的处理函数
    // throttleDelay节流延迟时间
    // isExecuteAgain是否第二次执行
  let timeoutId;
  let lastExecTime = 0;
  let inThrottle =  false;// 标记是否正在节流期内
  return function (...args) {
    const currentTime = Date.now();
    if (isExecuteAgain) {//      第一次调用	 立即执行,最后一次调用	 延迟执行,适用窗口调整等
      if (currentTime - lastExecTime > throttleDelay) {
        func.apply(this, args);
        lastExecTime = currentTime;
      } else {
        clearTimeout(timeoutId);
        timeoutId = setTimeout(() => {
          func.apply(this, args);
          lastExecTime = Date.now();
        }, throttleDelay);
      }
    } else {//      第一次调用	 立即执行,最后一次不执行	 适用按钮防重复点击、表单提交
      // 如果不在节流期内，执行函数
      if (!inThrottle) {
        // 执行目标函数
        func.apply(this, args);

        // 进入节流期
        inThrottle = true;

        // 设置定时器，在延迟时间后退出节流期
        setTimeout(() => {
          inThrottle = false;
        }, throttleDelay);
      }
    // 如果在节流期内，什么都不做（忽略调用）
    }   
  };
}
// 防抖函数
function debounce(func, debounceDelay, immediate = false) {
    // func处理函数
    // debounceDelay延迟时间
    // immediate是否立即执行，true立即执行，false不立即执行（防抖）

  let timeoutId; 
  return function (...args) {  
    clearTimeout(timeoutId);
    if (immediate && !timeoutId) {
      func.apply(this, args);
    }
    timeoutId = setTimeout(() => {
      timeoutId = null;
      if (!immediate) {
        func.apply(this, args);
      }
    }, debounceDelay);
  };
}
//首页导航页面代码

function isPageVisible({_,document}) { 
  // 定义一个函数来检测页面是否可见// 监控可见性变化
  if (typeof document.hidden !== 'undefined') {
      document.addEventListener('visibilitychange', function () {
        if (document.hidden) {
          // ('页面被隐藏了');        
        } else {
          onClick_search({isExecute:_.state.isExecuteClick,_})
          // ('页面被激活了');
        }
      });
    } else {
      // 监控焦点变化
      window.addEventListener('focus', function () {
        onClick_search({isExecute:_.state.isExecuteClick,_})
        //('页面获得了焦点');
      });
      // window.addEventListener('blur', function () {
      //  ('页面失去了焦点');
      // });
    }
}
async function pageOptionChange({e,_,tabName}) {//页面选择改变事件
  try {
    const { fieldNames, actionColumn } = _.state
    let { index: activeIndex, name } = e.currentTarget ? e.currentTarget.dataset : {};
      activeIndex = Number(activeIndex)
      const columnsParams = setDataColumns(fieldNames, activeIndex);
      _.setState({
        dataSource: null,
        columnsParams,
        dialogTitle: true,
        activeIndex,
      })
      await onClick_search({isExecute:true,_})
      const tableElement = _.$(tabName);
      if (tableElement && actionColumn && actionColumn[name]) {
        tableElement.set('actionColumn', actionColumn[name]);
      }   
  } catch (e){
    // 可根据需要添加错误处理逻辑
    console.error('Error in pageOptionChange:', error);
  }
}
function setDataColumns(fieldNames, activeIndex) {
  let columnsParams = []
  fieldNames[activeIndex].map(item => {
    if (item[2].isRender) {
      columnsParams.push({
        "title": item[0],
        "dataKey": item[1],
        ...item[2]
      })
    }
  })
  return columnsParams
}

async function setPublicVariable({_,addVars={}}) { // 设置js数据源,未绑定到组件的公共变量或需要更新的变量，宜搭20250609回复不保证稳定性
  let { pageNames, fieldNames, activeIndex, formUuids } = _.state
  let appType = window.pageConfig.appType || window.g_config.appKey
  let columnsParams = setDataColumns(fieldNames, activeIndex)
  const filterObjects = getFilterObjects()//复杂查询条件构造对象
  let otherVariables = {
    ...window.loginUser,
    ...{
      pageSize: 10,//分页数量，查询接口返回数量，最大100
      dialogTitle: true,//决定查询、导出excel      
      isMobile: _.utils.isMobile(),//是否是移动端
      isDingTalk:window.navigator && /dingtalk/i.test(window.navigator.userAgent),//是否在钉钉环境下
      isAutoExecute: true,//是否自动刷新数据任务
      isExecuteClick:true,//是否是否执行查询按钮动作
      appType,//应用id
      formUuid:window.pageConfig.formUuid || window.g_config.index//页面id
    }
  };
  // 更安全的数组初始化方式（避免所有元素引用同一个数组）
  const initialArray = Array.from({ length: 100 }, () => []);
  let [
    setShowFields, //显示字段配置
    defaultShows, //默认显示字段
    setQueryFields, //查询字段
    setQueryValues,//查询键值
    conditions, //查询条件
    buttonTitles,//显示对话框是否显示全选或全不选
    dateStartEnds,//查询起始日期
    dateFormat,//收集日期字段
    pageNumbers,//分页序号
    editUrls, //编辑跳转地址
    inputUrls,  //新增跳转地址 
  ] = initialArray
  let baseUrl = "https://www.aliwork.com"//主域名
  let path = {
    custom: "custom",//表单输入
    formDetail: 'formDetail'//实例详情
  }
  let urlParamsString = new URLSearchParams({
    corpid: 'ding133adf9bcfaef5f2ffe93478753d9884',//组织系统标识
    isRenderNav: "false",//false不显示导航栏，true显示
    ddtab: true,//true新窗口打开，false当前窗口打开
  }).toString();
  try {
    pageNames.forEach((item, index) => {
      [setShowFields, defaultShows, setQueryFields].forEach(arr => arr.push([]));
      [setQueryValues, conditions].forEach(obj => obj.push({}))
      dateStartEnds.push([null, null, null])
      pageNumbers.push(1)
      buttonTitles.push(true)
      inputUrls.push(`${baseUrl}/${appType}/${path.custom}/${formUuids[index]}?${urlParamsString}`)
      editUrls.push(`${baseUrl}/${appType}/${path.formDetail}/${formUuids[index]}`)
    })
    fieldNames.forEach((item, index) => {
      let x = 0
      item.forEach((child, childIndex) => {
        if (/dateField.*/ig.test(child[1])) {
          dateFormat.push(child[0])
        }
        if (child[3]) {
          let tem = { text: child[0], value: child[1] }
          if (child[4]) {
            Object.assign(tem, child[4])
          }
          setQueryFields[index].push(tem)
          setQueryValues[index][child[1]] = setQueryValues[index][child[1]] || ""
        }
        if (!child[5]) {
          if (!child[2].hidden) { defaultShows[index].push(x.toString()) }
          setShowFields[index].push({ text: child[0], value: x.toString() })
          x++
        }
      })
    })
    _.setState({
      queryAreaRender:Date.now(),//重置查询条件时，重新渲染查询区域值
      filterObjects,
      pageNumbers,
      editUrls,
      inputUrls,
      columnsParams,
      dateFormat,
      buttonTitles,
      setQueryValues,
      conditions,
      dateStartEnds,
      pageNumbers,
      setShowFields,
      defaultShows,
      setQueryFields,
      ...otherVariables,//合并其他变量
      ...addVars//额外增加的变量
    })
  } catch (e) {
    console.log(e)
  }
}
function setNavContent({_, isDingTalk, div1, div2,isExecute}) {//配置功能去、滑动区元素样式      
    let nav = document.getElementById(div1)
    let content = document.getElementById(div2)
    let parentHeight = window.innerHeight;
    let navHeight = nav.offsetHeight//56   
    parentHeight =  parentHeight - navHeight*3 //不知道为何要*3，才能计算出准确高度，避免父元素出现垂直滚动条，表格高度，iframe等高度，【滑动区  元素    】
    _.setState({parentHeight}) 
    if (isDingTalk && isExecute) {//钉钉端内生效        
        nav.style.position = '-webkit-sticky'
        nav.style.position = 'fixed'
        content.style.position = 'absolute'
        if (nav && content) {
            //  content.style.position = 'fixed'
            // content.style.top = navHeight + 'px'
        content.style["margin-top"] = navHeight + 'px'     
        }
    }
  
  
}
 function getScreenInfo(isSet) {//获取屏幕信息
    let { width, height, availWidth, availHeight } = window.screen
    let { outerWidth, outerHeight,
      innerWidth, innerHeight,   
    } = window
    if(isSet){
        isSet.setState({width, height,
      availWidth, availHeight,
      outerWidth, outerHeight,
      innerWidth, innerHeight,})
    } else {
        return {
            width, height,
            availWidth, availHeight,
            outerWidth, outerHeight,
            innerWidth, innerHeight,
        } 
    }
    
}
function setdisplay({ isDingTalk}) {  //设置操作、导航区域是否可见  
  if (isDingTalk) {
    let css = [
      '.next-aside-navigation',
      '.next-shell-header',
      '.next-shell-appbar',
      ".next-shell-action",
    ]
    let target = null
    for (let i = 0; i < css.length; i++) {
      target = document.querySelector(css[i])
      if (target) {
        target.setAttribute("style", "display: none !important;")
      }
    }
  }
}
 function dialogMove(id) {//拖动对话框，可缩放
  let dialog = document.getElementById(id);
  // console.log(dialog)
  if (!dialog) return;

  let isDragging = false;
  let isResizing = false;
  let resizeDirection = null;
  let offsetX, offsetY;
  let startX, startY;
  let startWidth, startHeight;
  let startLeft, startTop;

  // 添加标题栏拖拽事件
  const titleArea = dialog.querySelector('.title-area');
  // console.log(titleArea)
  titleArea.addEventListener('mousedown', (e) => {    
      startDragging(e);
    
  });

  // 添加调整大小事件
  const resizers = dialog.querySelectorAll('.resizer');
  resizers.forEach(resizer => {
    resizer.addEventListener('mousedown', (e) => {
      e.preventDefault();
      startResizing(e, resizer.classList[1]);
    });
  });

  // 开始拖拽
  function startDragging(e) {
    isDragging = true;
    offsetX = e.clientX - dialog.offsetLeft;
    offsetY = e.clientY - dialog.offsetTop;
    dialog.style.cursor = 'move';
    dialog.style.userSelect = 'none';
    dialog.classList.add('active');
  }

  // 开始调整大小
  function startResizing(e, direction) {
    isResizing = true;
    resizeDirection = direction;
    startX = e.clientX;
    startY = e.clientY;
    startWidth = parseInt(getComputedStyle(dialog).width, 10);
    startHeight = parseInt(getComputedStyle(dialog).height, 10);
    startLeft = dialog.offsetLeft;
    startTop = dialog.offsetTop;
    dialog.classList.add('active');
  }

  // 鼠标移动事件
  document.addEventListener('mousemove', (e) => {
    if (isDragging) {
      // 处理拖拽
      let x = e.clientX - offsetX;
      let y = e.clientY - offsetY;

      // 限制边界
      // x = Math.max(0, Math.min(x, window.innerWidth - dialog.offsetWidth));
      // y = Math.max(0, Math.min(y, window.innerHeight - dialog.offsetHeight));
      x = Math.max(0, Math.min(x, window.innerWidth));
      y = Math.max(0, Math.min(y, window.innerHeight));

      dialog.style.left = `${x}px`;
      dialog.style.top = `${y}px`;
    } else if (isResizing) {
      // 处理调整大小
      let width = startWidth;
      let height = startHeight;
      let left = startLeft;
      let top = startTop;

      // 根据方向计算新的大小和位置
      if (resizeDirection.includes('e')) {
        width = startWidth + (e.clientX - startX);
      }
      if (resizeDirection.includes('s')) {
        height = startHeight + (e.clientY - startY);
      }
      if (resizeDirection.includes('w')) {
        width = startWidth - (e.clientX - startX);
        left = startLeft + (e.clientX - startX);
      }
      if (resizeDirection.includes('n')) {
        height = startHeight - (e.clientY - startY);
        top = startTop + (e.clientY - startY);
      }

      // 最小尺寸限制
      width = Math.max(300, width);
      height = Math.max(300, height);

      // 边界限制
      if (resizeDirection.includes('w') && left < 0) {
        width += left;
        left = 0;
        width = Math.max(300, width);
      }

      if (resizeDirection.includes('n') && top < 0) {
        height += top;
        top = 0;
        height = Math.max(300, height);
      }

      // 应用新的大小和位置
      dialog.style.width = `${width}px`;
      dialog.style.height = `${height}px`;
      dialog.style.left = `${left}px`;
      dialog.style.top = `${top}px`;
    }
  });

  // 鼠标释放事件
  document.addEventListener('mouseup', () => {
    if (isDragging || isResizing) {
      isDragging = false;
      isResizing = false;
      dialog.style.cursor = '';
      dialog.style.userSelect = '';
      dialog.classList.remove('active');
    }
  });

  dialog.style.pointerEvents = 'auto';
}
function getFilterObjects() {
  // 重构复杂查询条件变量
  return {
    textField: {
      "key": "textField_kwod1oy2",
      "value": "A",
      "type": "TEXT",
      "operator": "like",
      "componentName": "TextField"
    },
    textareaField: {
      "key": "textareaField_kwod1oy4",
      "value": "A",
      "type": "TEXT",
      "operator": "like",
      "componentName": "TextareaField"
    },
    numberField: {
      "key": "numberField_kwod1oy6",
      "value": [1, 2],
      "type": "DOUBLE",
      "operator": "between",
      "componentName": "NumberField"
    },
    radioField: {
      "key": "radioField_kwod1oya",
      "value": ["选项一", "选项二"],
      "type": "ARRAY",
      "operator": "contains",
      "componentName": "RadioField"
    },
    selectField: {
      "key": "selectField_kwod1oya",
      "value": ["选项一", "选项二"],
      "type": "ARRAY",
      "operator": "contains",
      "componentName": "SelectField"
    },
    checkboxField: {
      "key": "checkboxField_kwod1oyc",
      "value": ["选项一", "选项三"],
      "type": "ARRAY",
      "operator": "contains",
      "componentName": "CheckboxField"
    },
    multiSelectField: {
      "key": "multiSelectField_kwod1oyg",
      "value": ["选项一", "选项二"],
      "type": "ARRAY",
      "operator": "contains",
      "componentName": "MultiSelectField"
    },
    dateField: {
      "key": "dateField_kwod1oyi",
      "value": [0, Date.now()],
      "type": "DOUBLE",
      "operator": "between",
      "componentName": "DateField"
    },
    cascadeDateField: {
      "key": "cascadeDateField_kwod1oyk",
      "value": [
        [0, Date.now()],
        [0, Date.now()]
      ],
      "type": "DOUBLE",
      "componentName": "CascadeDateField"
    },
    imageField: {
      "key": "imageField_kwod1oyq",
      "value": "fileUpload/",
      "type": "TEXT",
      "operator": "like",
      "componentName": "ImageField"
    },
    attachmentField: {
      "key": "attachmentField_kwod1oys",
      "value": "APP_ANNSASAS",
      "type": "TEXT",
      "operator": "like",
      "componentName": "AttachmentField"
    },
    employeeField: {
      "key": "employeeField_kwod1oym",
      "value": "钉钉userId",
      "type": "STRING",
      "operator": "eq",
      "componentName": "EmployeeField"
    },
    tableField:{
      "key": "tableField_kwod1oyu",
      "value": "关键词",
      "type": "TEXT",
      "operator": "contains",
      "componentName": "TableField"
    },
    详细说明链接: "https://open.dingtalk.com/document/orgapp/use-the-filter-conditions-in-the-form-data-management-for"
  }
}
function paramsChecks(params) {//全部数据查询函数参数检测
  const { dpName, formUuid, searchFieldJson, dynamicOrder } = params;
  if (!dpName) throw new Error('dpName参数必填');
  if (!formUuid) throw new Error('formUuid参数必填');
  if (typeof dpName !== 'string') throw new Error('dpName参数数据格式错误');
  if (typeof formUuid !== 'string') throw new Error('formUuid参数数据格式错误');
  if (searchFieldJson && !(typeof searchFieldJson === 'object' && searchFieldJson !== null)) {
    throw new Error('searchFieldJson参数数据格式错误');
  }
  if (dynamicOrder && !(typeof dynamicOrder === 'object' && dynamicOrder !== null && !Array.isArray(dynamicOrder))) {
    throw new Error('dynamicOrder参数数据格式错误');
  }
}
async function upData({params,_}) {//formInstIds包含表单唯一标识的文本数组 
  let { dpName = 'updateFormData',  formInstIds,updateFormDataJsons } = params || {}    
  let result = { successes: [], failures: [] }; // 执行结束后返回数据  ，成功失败数量  
  let tasks = [], successes = [], failures = []
  // tasks存储所有请求的Promise，用于最后返回所有结果  
  const executing = new Set(), maxConcurrent = 10//// 更新接口建议：10内已测试未出现问题，之上限流
  //  executing使用Set来跟踪当前正在执行的请求,Set会自动去重，适合用来跟踪运行中的Promise
   try{
    for (let i = 0; i < formInstIds.length; i++) {
      let promise =_.dataSourceMap[dpName].load({
        formInstId: formInstIds[i],
        useLatestVersion: "y",
        updateFormDataJson:JSON.stringify(updateFormDataJsons[i]),
      }).then(res => res)
      tasks.push(promise) // 将当前请求的Promise存入结果数组    
      executing.add(promise)// 将当前请求的Promise添加到执行跟踪Set中
      promise.finally(() => executing.delete(promise))    // 无论请求成功还是失败，当请求完成时从执行跟踪Set中移除      
      // 如果当前正在执行的请求数量达到最大并发数
      if (executing.size >= maxConcurrent) {
        // 使用Promise.race等待任意一个正在执行的请求完成， 这样就能释放一个"并发槽位"给下一个请求
        await Promise.race(executing);
      }
    }
  } catch (e) {
    throw new Error(e.message)
  } finally {
    // 当所有请求都已开始后，等待所有请求完成，使用Promise.allSettled等待所有请求的Promise完成
    const results = await Promise.allSettled(tasks);
    successes = results
      .filter(result => result.status === 'fulfilled')//筛选成功的
      .reduce((acc, curr) => {//合并为数组
        return [...acc, ...curr.value];
      }, [])
    failures = results
      .reduce((acc, curr, index) => {
        if (curr.status === 'rejected') {
          curr.reason.index = index//原数组失败索引值加入到reason对象中
          acc.push(curr)
        }
        return acc
      }, [])//筛选失败
      .reduce((acc, curr) => {//合并为数组       
        return [...acc, ...curr.reason];
      }, [])
    Object.assign(result, { successes, failures })    
    return result
  }
}
async function saveDatas({params,_}) {//20250605异步并发保存，提高写入速度，已做限流措施
    let { dpName = 'saveFormData', formDataJsons } = params || {}    
    let result = { successes: [], failures: []}; // 执行结束后返回数据  ，成功失败数量
    let tasks = [], successes = [], failures = []
    // tasks存储所有请求的Promise，用于最后返回所有结果  
    const executing = new Set(), maxConcurrent = 50//// 写入接口建议：2000内已测试未出现问题
        //  executing使用Set来跟踪当前正在执行的请求,Set会自动去重，适合用来跟踪运行中的Promise
    try {
        for (let i = 0; i < formDataJsons.length; i++) {
            let promise = _.dataSourceMap[dpName].load({           
            formDataJson: JSON.stringify(formDataJsons[i]),
            }).then(res => res)
            tasks.push(promise) // 将当前请求的Promise存入结果数组    
            executing.add(promise)// 将当前请求的Promise添加到执行跟踪Set中
            promise.finally(() => executing.delete(promise))    // 无论请求成功还是失败，当请求完成时从执行跟踪Set中移除
            
            // 如果当前正在执行的请求数量达到最大并发数
            if (executing.size >= maxConcurrent) {
            // 使用Promise.race等待任意一个正在执行的请求完成， 这样就能释放一个"并发槽位"给下一个请求
            await Promise.race(executing);
            }
        }
    } catch (e) {
        throw new Error(e.message)
    } finally {
        // 当所有请求都已开始后，等待所有请求完成，使用Promise.allSettled等待所有请求的Promise完成
        const results = await Promise.allSettled(tasks);
        successes = results
            .filter(result => result.status === 'fulfilled')//筛选成功的
            .reduce((acc, curr) => {//合并为数组
            return [...acc, ...curr.value];
            }, [])
        failures = results
            .reduce((acc, curr, index) => {
            if (curr.status === 'rejected') {
                curr.reason.index = index//原数组失败索引值加入到reason对象中
                acc.push(curr)
            }
            return acc
            }, [])//筛选失败
            .reduce((acc, curr) => {//合并为数组       
            return [...acc, ...curr.reason];
            }, [])
        Object.assign(result, { successes, failures })
        return result
    }  
}
async function getTableDatas({ params, _ }) {//获取所有子表数据
  let {
    dpName = 'listTableDataByFormInstIdAndTableId', //远程数据源名
    formUuid,//表单 ID
    formInstanceId,//要查询的实例的实例 ID
    tableFieldId,//需要查找的子表单组件的唯一标识
    pageSize = 49//每页记录数
  } = params || {}
  let result = { successes: [], failures: [], totalCount: 0 }; // 最终数据  
  let datas = await _.dataSourceMap[dpName].load({
    formUuid,//表单 ID
    formInstanceId,//要查询的实例的实例 ID
    tableFieldId,//需要查找的子表单组件的唯一标识
  }).catch(error => {
    _.utils.toast({
      title: error.message,
      type: 'error',
    });
    result.failures.push(error.message)
  });
  if (!datas) {
    result.failures.push('数据源不存在')
    return result
  };
  let total = datas.totalCount
  result.totalCount = total
  if (total  < 50) {
    //当子表数据总数不大于50时
    result.successes = datas.data //归整数据
    return result
  } else {
    //当实例总数大于100时
    let tasks = [], successes = [], failures = []
    // tasks存储所有请求的Promise，用于最后返回所有结果
    const executing = new Set(), maxConcurrent = 20//并发执行最大数量，10个最稳定，30个可以考虑，50个有风险
      //  executing使用Set来跟踪当前正在执行的请求,Set会自动去重，适合用来跟踪运行中的Promise
    try {
      for (let i = 0; i < Math.ceil(total / 49); i++) {       
        //遍历所有查询语句
        let promise = _.dataSourceMap[dpName].load({
          formUuid,//表单 ID
          formInstanceId,//要查询的实例的实例 ID
          tableFieldId,//需要查找的子表单组件的唯一标识
          pageSize: 49,//每页记录数
          currentPage : i + 1//当前页
        }).then(res => res.data)// 创建单个请求的Promise
        tasks.push(promise) // 将当前请求的Promise存入结果数组    
        executing.add(promise)// 将当前请求的Promise添加到执行跟踪Set中
        promise.finally(() => executing.delete(promise))    // 无论请求成功还是失败，当请求完成时从执行跟踪Set中移除
        // 如果当前正在执行的请求数量达到最大并发数
        if (executing.size >= maxConcurrent) {
          // 使用Promise.race等待任意一个正在执行的请求完成， 这样就能释放一个"并发槽位"给下一个请求
          await Promise.race(executing);
        }
      }
    } catch (e) {
      throw new Error(e.message)
    } finally {
      // 当所有请求都已开始后，等待所有请求完成，使用Promise.allSettled等待所有请求的Promise完成
      const results = await Promise.allSettled(tasks);
      successes = results
        .filter(result => result.status === 'fulfilled')//筛选成功
        .reduce((acc, curr) => {//合并为数组
          return [...acc, ...curr.value];
        }, [])
      failures = results
        .reduce((acc, curr, index) => {
          if (curr.status === 'rejected') {
            curr.reason.index = index//原数组失败索引值加入到reason对象中
            acc.push(curr)
          }
          return acc
        }, [])//筛选失败
        .reduce((acc, curr) => {//合并为数组          
          return [...acc, ...curr.reason];
        }, [])
      Object.assign(result, { successes, failures })
      return result
    }
  };

}
async function getAllDatas({params,_}) {//20250603改进查询全部数据函数,已做限流措施
  let { dpName = 'searchFormDatas', formUuid, searchFieldJson, dynamicOrder,max = 20 } = params || {}
  let result = { successes: [], failures: [], totalCount: 0 }; // 最终数据
  try {//检查传入参数是否准确paramsChecks
    paramsChecks({ dpName, formUuid, searchFieldJson, dynamicOrder })
    let datas = await _.dataSourceMap[dpName].load({
      formUuid,
      searchFieldJson: JSON.stringify(searchFieldJson),
      pageSize: 100
    }).catch(error => {
      result.failures.push(error.message)
    })       
    if (!datas) {
      result.failures.push('数据源不存在')
      return result
    };
    let total = datas.totalCount
    result.totalCount = total
    if (total <= 100) {
      //当实例总数不大于100时
      result.successes = datas.data //归整数据
      return result
    } else {
      //当实例总数大于100时
      let tasks = [], successes = [], failures = []
      // tasks存储所有请求的Promise，用于最后返回所有结果
      const executing = new Set(), maxConcurrent = max//并发执行最大数量，10个最稳定，30个可以考虑，50个有风险
      //  executing使用Set来跟踪当前正在执行的请求,Set会自动去重，适合用来跟踪运行中的Promise
      try {
        for (let i = 0; i < Math.ceil(total / 100); i++) {
          //遍历所有查询语句
          let promise = _.dataSourceMap[dpName].load({// 创建单个请求的Promise
            formUuid,
            searchFieldJson: JSON.stringify(searchFieldJson),
            pageSize: 100,
            currentPage: i + 1,
            dynamicOrder: JSON.stringify(dynamicOrder)
          }).then(res => res.data)
          tasks.push(promise) // 将当前请求的Promise存入结果数组    
          executing.add(promise)// 将当前请求的Promise添加到执行跟踪Set中
          promise.finally(() => executing.delete(promise))    // 无论请求成功还是失败，当请求完成时从执行跟踪Set中移除

          // 如果当前正在执行的请求数量达到最大并发数
          if (executing.size >= maxConcurrent) {
            // 使用Promise.race等待任意一个正在执行的请求完成， 这样就能释放一个"并发槽位"给下一个请求
            await Promise.race(executing);
          }
        }
      } catch (e) {
        throw new Error(e.message)
      } finally {
        // 当所有请求都已开始后，等待所有请求完成，使用Promise.allSettled等待所有请求的Promise完成
        const results = await Promise.allSettled(tasks);
        successes = results
          .filter(result => result.status === 'fulfilled')//筛选成功
          .reduce((acc, curr) => {//合并为数组
            return [...acc, ...curr.value];
          }, [])
        failures = results
          .reduce((acc, curr, index) => {
            if (curr.status === 'rejected') {
              curr.reason.index = index//原数组失败索引值加入到reason对象中
              acc.push(curr)
            }
            return acc
          }, [])//筛选失败
          .reduce((acc, curr) => {//合并为数组          
            return [...acc, ...curr.reason];
          }, [])
        Object.assign(result, { successes, failures })
        return result
      }


    };
  } catch (e) {
    throw new Error(e.message)
  }

}

async function onClick_search({isExecute,_}) {//点击查询代码和导出excel代码
  let { activeIndex, setQueryValues, pageNumbers,  conditions, dateFormat,isExecuteClick,
    dateFields, isAutoExecute, dateStartEnds, dialogTitle, fieldNames, formUuids, filterObjects } = _.state
  if (!isAutoExecute  ) {//定义是否执行自动查询   
    if (!isExecute) { return }//当出于导出excel状态时，不执行自动刷新
  }
  let obj = {}
  let setQueryValue = setQueryValues[activeIndex]
  for (let item in setQueryValue) {
    let tem = setQueryValue[item]
    if (tem) { obj[item] = tem }
  }
  
  pageNumbers[activeIndex] = 1
  let dateField = dateFields[activeIndex]
  if (dateStartEnds[activeIndex][0] && dateStartEnds[activeIndex][1]) {
    obj[dateField] = dateStartEnds[activeIndex]
  }
  let filters = []//添加复杂查询条件
  if (Object.keys(obj).length) {
    for (let key in obj) {
      let newK = key.replace(/_[\da-zA-Z]+$/, '')
      let value = obj[key]
      if (filterObjects[newK]){
        filters.push({ ...filterObjects[newK], key, value })
      }    
    }
  }

  conditions[activeIndex] = filters
  _.setState({
    pageNumbers: pageNumbers,
    conditions: conditions,
  })
  let toastSearch = _.utils.toast({
    title: dialogTitle ? "数据加载中……" : '正在导出数据……',
    type: 'loading',
    size: 'large',
  });
  
  if (dialogTitle) {
    await _.dataSourceMap.searchFormDatas.load();
    toastSearch()
  } else {
    try {
      let header = [], arr = fieldNames[activeIndex]
      for (let item of arr) {//excel标题对象数组      
        if (!item[5]) { header.push({ title: item[0], value: item[1] }) }//筛选不需要导出的字段
      }
      let dpName = "searchFormDatas"
      let formUuid = formUuids[activeIndex]
      let params = {
        dpName, formUuid,
        searchFieldJson: filters
      }
      let res = await getAllDatas({params,_})
      if (res.successes.length) {
        await onExportData(res.successes, header, activeIndex, dateFormat,_)
      } else {
        _.utils.toast({
          title: '无导出数据',
          type: 'warning',
          size: 'large',
          duration: 2000,
        });
      }
      toastSearch()
    } catch (e) {
      _.utils.toast({
        title: e.message,
        type: 'error',
      });
      toastSearch()
    }
  }
}

async function onClick_Total({_}) {//点击汇总
    let toastSearch = _.utils.toast({
        title: "数据处理中……" ,
        type: 'loading',
        size: 'large',
    });
    let res = null
    try {
        let { activeIndex, setQueryValues, pageNumbers,  conditions, dateFormat,isExecuteClick,
        dateFields, isAutoExecute, dateStartEnds, dialogTitle, fieldNames, formUuids, filterObjects } = _.state
        let obj = {}
        let setQueryValue = setQueryValues[activeIndex]
        for (let item in setQueryValue) {
            let tem = setQueryValue[item]
            if (tem) { obj[item] = tem }
        }
        pageNumbers[activeIndex] = 1
        let dateField = dateFields[activeIndex]
        if (dateStartEnds[activeIndex][0] && dateStartEnds[activeIndex][1]) {
            obj[dateField] = dateStartEnds[activeIndex]
        }
        let filters = []//添加复杂查询条件
        if (Object.keys(obj).length) {
            for (let key in obj) {
            let newK = key.replace(/_[\da-zA-Z]+$/, '')
            let value = obj[key]
            if (filterObjects[newK]){
                filters.push({ ...filterObjects[newK], key, value })
            }    
            }
        }
        conditions[activeIndex] = filters
        _.setState({
            pageNumbers: pageNumbers,
            conditions: conditions,
        })
        

        let dpName = "searchFormDatas"
        let formUuid = formUuids[activeIndex]
        let params = {
        dpName, formUuid,
        searchFieldJson: filters
        }
        res = await getAllDatas({params,_})        
    } catch (e) {
      _.utils.toast({
        title: e.message,
        type: 'error',
      });      
    }      
    toastSearch()    
    return res   
}
 async function onExportData(records, sheetHeader, index, dateFormat,_) {//导出excel
  if (!records.length || !records) {
    _.utils.toast({
      title: '当前未获得任何数据',
      type: 'warning'
    });
    return;
  };
  let isSet = dateFormat ? true : false
  let widths = new Array(sheetHeader.length)
  const result = [];
  for (let i = 0; i < records.length; i++) {
    let item = {};
    for (let j = 0; j < sheetHeader.length; j++) {
      let temData = records[i][sheetHeader[j].value]
      if (temData) {
        if (temData.length * 2 > (widths[j] ? widths[j] : 0)) {
          widths[j] = temData.length * 2// 中文占2个字符
        }
        if (isSet) {
          if (dateFormat.indexOf(sheetHeader[j].title) > -1) {
            temData = dateToStrings(temData).nowDate
          }
        }
      } else if (temData == undefined) {
        temData = ''
      }
      item[sheetHeader[j].title] = temData;
    };
    result.push(item);
  };
  // 新建空workbook，然后加入worksheet
  const ws = XLSX.utils.json_to_sheet(result);
  // 设置每列的列宽，10代表10个字符，注意中文占2个字符
  ws['!cols'] = []
  for (let w = 0; w < sheetHeader.length; w++) {
    ws['!cols'].push({ wch: widths[w] > 20 ? widths[w] : 20 })
  }
  // ws['!cols'] = [
  //   { wch: 10 },
  //   { wch: 10 },
  //   { wch: 10 }
  // ];
  // 新建book
  const wb = XLSX.utils.book_new();
  // 生成xlsx文件(book,sheet数据,sheet命名)
  XLSX.utils.book_append_sheet(wb, ws, 'sheet1');
  // 写文件
  const workbookBlob = workbook2blob(wb);
  await openDownloadDialog(workbookBlob, `${_.state.pageNames[index]}${_.utils.formatter('date', Date.now(), 'YYYYMMDDhhmmss')}.xlsx`);
}
function openDownloadDialog(blob, fileName) {
  if (typeof blob == "object" && blob instanceof Blob) {
    blob = URL.createObjectURL(blob); // 创建blob地址
  }
  var aLink = document.createElement("a");
  aLink.href = blob;
  // HTML5新增的属性，指定保存文件名，可以不要后缀，注意，有时候 file:///模式下不会生效
  aLink.download = fileName || "";
  var event;
  if (window.MouseEvent) {
    event = new MouseEvent("click");//   移动端
  } else {
    event = document.createEvent("MouseEvents");
    event.initMouseEvent("click", true, false, window, 0, 0, 0, 0, 0, false,
      false, false, false, 0, null);
  }
  aLink.dispatchEvent(event);
}

function workbook2blob(workbook) {
  // 生成excel的配置项
  var wopts = {
    // 要生成的文件类型
    bookType: "xlsx",
    bookSST: false,
    type: "binary"
  };
  var wbout = XLSX.write(workbook, wopts);
  // 将字符串转ArrayBuffer
  function s2ab(s) {
    var buf = new ArrayBuffer(s.length);
    var view = new Uint8Array(buf);
    for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff;
    return buf;
  }
  var blob = new Blob([s2ab(wbout)], {
    type: "application/octet-stream"
  });
  return blob;
}
//日期数据转字符串数据
function dateToStrings(dateValue) {
  let now = new Date(dateValue)
  const nowYear = now.getFullYear()
  const nowMonth = now.getMonth() + 1
  const nowDay = now.getDate()
  const nowDate = nowYear + '/' + ((nowMonth < 10) ? ('0' + nowMonth) : nowMonth) + '/' + ((nowDay < 10) ? ('0' + nowDay) : nowDay)
  const weekNum = now.getDay()
  const week = weekNum ? weekNum : 7
  const hour = now.getHours()
  const minute = now.getMinutes()
  const second = now.getSeconds()
  const nowTime = ((hour < 10) ? ('0' + hour) : hour) + ':' + ((minute < 10) ? ('0' + minute) : minute)
  let x = hour + minute 
  let result = {
    second: second,
    week: week,
    nowDate: nowDate,
    nowTime: nowTime,
    now: nowDate + (x ? ' ' + nowTime : ''),
    dateTimeArray: [nowYear, nowMonth < 10 ? ('0' + nowMonth) : nowMonth, nowDay < 10 ? ('0' + nowDay) : nowDay,
      hour < 10 ? ('0' + hour) : hour, minute < 10 ? ('0' + minute) : minute, second < 10 ? ('0' + second) : second//年月日时分数组
    ]
  }
  return result
}
function isAllSelected({option,_}) {//全选与否
  let { buttonTitles, defaultShows,
    activeIndex, columnsParams, dataSource, fieldNames } = _.state
  let arr = [], isSeleted = option === '全选'
  let t = 0
  for (let i = 0; i < fieldNames[activeIndex].length; i++) {
    if (fieldNames[activeIndex][i][2].isRender) {
      fieldNames[activeIndex][i][2].hidden = !isSeleted
      if (isSeleted) {
        arr.push(String(i))
      }
      columnsParams[t].hidden = !isSeleted
      t++
    }
  }
  defaultShows[activeIndex] = arr//设置默认选中，避免切换后要重复设置
  buttonTitles[activeIndex] = !isSeleted
  //此段代码强制更新数据一遍刷新表格显示状态
  let obj = dataSource || {}
  obj['up' + Math.random()] = Math.random()
  dataSource = obj
  //此段代码强制更新数据一遍刷新表格显示状态
  _.setState({
    columnsParams,
    fieldNames,
    defaultShows,
    buttonTitles,
    dataSource
  })
};
function getMoreSelsectChange({selecteds,_}) {  //显示隐藏列 
  let {defaultShows, activeIndex,
    columnsParams, dataSource, fieldNames } = _.state
  let arr = [], t = 0
  for (let i = 0; i < fieldNames[activeIndex].length; i++) {
    if (fieldNames[activeIndex][i][2].isRender) {
      let b = selecteds.indexOf(i.toString()) === -1
      fieldNames[activeIndex][i][2].hidden = b
      if (!b) {
        arr.push(String(i))
      }
      columnsParams[t].hidden = b
      t++
    }
  }
  defaultShows[activeIndex] = arr//设置默认选中，避免切换后要重复设置
  //此段代码强制更新数据一遍刷新表格显示状态
  let obj = dataSource || {}
  obj['up' + Math.random()] = Math.random()
  dataSource = obj
  //此段代码强制更新数据一遍刷新表格显示状态
  _.setState({
    columnsParams,
    fieldNames,
    defaultShows,
    dataSource
  })
}
async function setScript(scriptUrls) {//页面初始事件中加载，同步，加载远程js资源,【特别适合sdk】
  const tasks = scriptUrls.map(url => {
    return new Promise((resolve, reject) => {
      let script = document.createElement('script');
      script.setAttribute('type', 'text/javascript');
      script.src = url
      script.onload = () => resolve(url); // 成功时解析URL
      script.onerror = () => reject(new Error(`Failed to load script: ${url}`));
      document.body.appendChild(script);     
    })
  })
  
  const results = await Promise.allSettled(tasks)
    let result = {
      successes: results
        .filter(result => result.status === 'fulfilled')//筛选成功
        .map(result => result.value), // 直接映射成功的URL
      failures: results
      .filter(result => result.status ==='rejected')
      .map(result => result.reason), // 直接映射成功的URL
    }    
  return result
}
function onClick_Reset(_) {//查询重置
  let { setQueryValues, dateStartEnds,activeIndex } =_.state
  let setQueryValue = setQueryValues[activeIndex]
  for (let item in setQueryValue) {   
    setQueryValue[item] = ""
  }
  dateStartEnds[activeIndex] = [null,null,null]
  setQueryValues[activeIndex] = setQueryValue
  let queryAreaRender = Date.now()
 _.setState({ setQueryValues, dateStartEnds,queryAreaRender })
}
function inputChangeJSX(e,_) {//获取查询对话框输入查询条件信息
    const { name, value } = e.target;     
    let { setQueryValues, activeIndex } = _.state 
    let setQueryValue = setQueryValues[activeIndex]      
    setQueryValue[name] = value
    setQueryValues[activeIndex] = setQueryValue
    _.setState({ setQueryValues})
 
} 

function scrollToTop() {//回到顶顶区域
  window.scrollTo({
    top: 0,
    left: 0,
    // behavior: 'smooth' // 可选，平滑滚动
  });
}
function showMore(rowData,_) {//查看原文
  let { editUrls, activeIndex} = _.state
  const formInstId = rowData.formInstId;
  let param =  {
    formInstId,
    corpid: 'ding133adf9bcfaef5f2ffe93478753d9884',//组织系统标识
    isRenderNav: "false",//false不显示导航栏，true显示
    ddtab: true,//true新窗口打开，false当前窗口打开
  }
  _.utils.router.push(editUrls[activeIndex ], param, true, true)
}
function goToEdit(rowData,_) {//跳转编辑页面
  if(rowData.event == false){return}//如果显示渲染不响应事件，则退出 
  const { activeIndex, editUrls } = _.state 
  const { formInstId } = rowData
  let param =  {
    isEdit:"y",
    formInstId,
    corpid: 'ding133adf9bcfaef5f2ffe93478753d9884',//组织系统标识
    isRenderNav: "false",//false不显示导航栏，true显示
    ddtab: true,//true新窗口打开，false当前窗口打开
  }
  _.utils.router.push(editUrls[activeIndex ], param, true, true)
}
function goToInputPage(_) {//跳转输入页面
  const { inputUrls, activeIndex } = _.state
  _.utils.router.push(inputUrls[activeIndex], {}, true, true)
}
function goToDelete(rowData,_) {//删除记录
  if (rowData.event === false) { return }   
  _.utils.dialog({
    type: 'confirm',
    title: '确认删除',
    content: '删除后数据无法恢复，是否确认删除',
    onOk: () => {
      let param = {
        formInstId: rowData.formInstId,
      };
      _.dataSourceMap['deleteFormData'].load(param).then(res => {
        _.utils.toast({
          title: "删除成功",
          type: "success",
          size: "large"
        });
        setTimeout(() => {
          _.dataSourceMap['searchFormDatas'].load();
        }, 500);
      })
    },
    onCancel: () => { },
  })    
  
}
function simulatedEvent({ selectedName, context, functionName}){
  //模拟元素单击事件,selectedName参数为元素id,, context为bind对象，此处是this 
  let element = document.getElementById(selectedName)
  element.addEventListener('click', context[functionName].bind(context), false);
  let event = new Event('click');
  element.dispatchEvent(event)
}
function arrObjectSort(keyName, sort) { //这是比较函数，以对象数组中对象属性值（数字），用数组sort方法arr.sort(arrObjectSort(属性名称))
  return function (m, n) {
    let a = Number(m[keyName]);
    let b = Number(n[keyName]);
    return sort ? (b - a) : (a - b); //升序 ;b-a倒序
  }
}

//表单代码
function getPageState(_) {//获取易搭页面状态
  let result = '提交页面'  
  if (!_.utils.isSubmissionPage()) {
    let instanceData = _.utils.getFormInstanceData();
    let { flowData = {} } = instanceData;
    let { editMode, viewMode } = flowData;
    
    if (editMode) {
      result = '编辑页面'
    } else if (viewMode) {
      result = '预览页面'
    }
  }
  return result
}
function clickAutoEditBtn(_) {// 进入详情页后是否自动进入编辑态，ditmount事件中加入此方法后的数据才生效
  // 链接样例https://www.aliwork.com/APP_GCNUSP4L2ZCPAPHEVGBU/formDetail/FORM-EF4379731D0F4146B2F4513CE15957E5CIG3?formInstId=FINST-RC966V71L7NNMI9O79NHA9SH132U3MA76PQZLRP1&isEdit=y
  if (!_.utils.isSubmissionPage()) {
    const { isEdit = '' } = _.state.urlParams;//url传递的参数名isEdit=y
    const instanceData = _.utils.getFormInstanceData();
    const { flowData = {} } = instanceData;
    const { viewMode } = flowData;   
    if (viewMode && isEdit && isEdit === 'y') {  //通过链接设置判断参数
      // if (viewMode)//通过详情按钮进入后
      setTimeout(() => {
        if (_.utils.isMobile()) {            
          // 移动
          const editDom = document.querySelectorAll('.new-bottom-bar .icon-box.edit');
          if (editDom.length) {
            editDom[0].click();
          }
        } else {          // PC
         
          const btnHelperDomList = document.querySelectorAll('.deep-button-group .next-btn-helper');
          // console.log(btnHelperDomList)
          if (btnHelperDomList.length) {
            for (let i = 0; i < btnHelperDomList.length; i++) {
              if (btnHelperDomList[i].innerText.includes('编辑')) {
                btnHelperDomList[i].parentNode.click();
                break;
              }
            }
          }
        }
      }, 1000)
    };
  }
}
async function setFormVariable({_,addVars={}}) { // 设置表单公共变量   
  let otherVariables = {
    ... window.loginUser,
    ...{           
      isMobile: _.utils.isMobile(),//是否是移动端
      isDingTalk:window.navigator && /dingtalk/i.test(window.navigator.userAgent),//是否在钉钉环境下
    //   appType: window.pageConfig.appType || window.g_config.appKey,//应用id
    //   formUuid:window.pageConfig.formUuid || window.g_config.index//页面id
    }
  }
   _.setState({      
      ...otherVariables,//合并其他变量
      ...addVars//额外增加的变量
    })

}
//表单代码